/*
 * UnitTest.cpp
 *
 *  Created on: Dec 3, 2011
 *      Author: shaohong
 */




#include "BitUtils.h"


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <iostream>
#include <sstream>

#include "ParsingUtils.h"
#include "SipMessage.h"
#include "SipHeader.h"
#include "NmpsException.h"
#include "SipServer.h"
#include "RadioStreamer.h"
#include "RadioChannel.h"


using namespace std;
using namespace nmps;


string sipInviteMsgStr;
string sipACKMsgStr;

void initializeInviteMsg(){

	stringstream ss;
	ss << "INVITE sip:francisco@bestel.com:55060 SIP/2.0" << '\x0d' << '\x0a'
			<<"Via: SIP/2.0/UDP 200.57.7.195;branch=z9hG4bKff9b46fb055c0521cc24024da96cd290" <<'\x0d' << '\x0a'
			<<"Via: SIP/2.0/UDP 200.57.7.195:55061;branch=z9hG4bK291d90e31a47b225bd0ddff4353e9cc0" << '\x0d' << '\x0a'
			<<"From: <sip:200.57.7.195:55061;user=phone>;tag=GR52RWG346-34"<< '\x0d' << '\x0a'
			<<"To: \"francisco@bestel.com\" <sip:francisco@bestel.com:55060>"<< '\x0d' << '\x0a'
			<<"Call-ID: 12013223@200.57.7.195"<< '\x0d' << '\x0a'
			<<"CSeq: 1 INVITE"<< '\x0d' << '\x0a'
			<<"Contact: <sip:200.57.7.195:5060>"<< '\x0d' << '\x0a'
			<<"Content-Type: application/sdp"<< '\x0d' << '\x0a'
			<<"Content-Length:  229"<< '\x0d' << '\x0a'
			<<'\x0d' << '\x0a'
			<<"v=0"<< '\x0d' << '\x0a'
			<<"o=Clarent 120386 120387 IN IP4 200.57.7.196"<< '\x0d' << '\x0a'
			<<"s=Clarent C5CM"<< '\x0d' << '\x0a'
			<<"c=IN IP4 200.57.7.196"<< '\x0d' << '\x0a'
			<<"t=0 0"<< '\x0d' << '\x0a'
			<<"m=audio 40376 RTP/AVP 8 18 4 0"<< '\x0d' << '\x0a'
			<<"a=rtpmap:8 PCMA/8000"<< '\x0d' << '\x0a'
			<<"a=rtpmap:18 G729/8000"<< '\x0d' << '\x0a'
			<<"a=rtpmap:4 G723/8000"<< '\x0d' << '\x0a'
			<<"a=rtpmap:0 PCMU/8000"<< '\x0d' << '\x0a'
			<<"a=SendRecv"<< '\x0d' << '\x0a';

	sipInviteMsgStr = ss.str();
}

void initializeAckMsg(){

	stringstream ss;
	ss << "ACK sip:192.168.126.131:5060 SIP/2.0" << '\x0d' << '\x0a'
	   <<"Via: SIP/2.0/UDP 192.168.126.131:5070;rport;branch=z9hG4bK1955723513" << '\x0d' << '\x0a'
	   <<"From: <sip:shaohong@192.168.126.131>;tag=230262326" << '\x0d' << '\x0a'
	   <<"To: <sip:192.168.126.131:5060>;tag=nmps-2011" << '\x0d' << '\x0a'
	   <<"Call-ID: 35787496" << '\x0d' << '\x0a'
	   <<"CSeq: 20 ACK" << '\x0d' << '\x0a'
	   <<"Contact: <sip:shaohong@192.168.126.131:5070>"<< '\x0d' << '\x0a'
	   <<"Max-Forwards: 70"<< '\x0d' << '\x0a'
	   <<"User-Agent: Linphone/3.2.1 (eXosip2/3.3.0)"<< '\x0d' << '\x0a'
	   <<"Content-Length: 0"<< '\x0d' << '\x0a'
	   << '\x0d' << '\x0a';

	sipACKMsgStr = ss.str();
}


void testGetBitValue() {

	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	uint32_t value = 0xFFFF; // all bits are 1

	for (int pos = 0; pos < 16; pos++) {
		assert(1 == BitUtils::getBitValue(value, pos));
	}

	value = 0xF0FF;
	for (int pos = 0; pos < 8; pos++) {
		assert(1 == BitUtils::getBitValue(value, pos));
	}

	for (int pos = 8; pos < 12; pos++) {
		assert(0 == BitUtils::getBitValue(value, pos));
	}

	for (int pos = 12; pos < 16; pos++) {
		assert(1 == BitUtils::getBitValue(value, pos));
	}

}

void testSetBitValue() {

	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	unsigned char byte = 0x23; // "00100011"
	BitUtils::setBitValue(&byte, 7, 1);

	assert( byte == 0xa3);	// "10100011"

	BitUtils::setBitValue(&byte, 6, 1);

	assert( byte == 0xE3);	// "11100011"

	BitUtils::setBitValue(&byte, 1, 0);

	assert( byte == 0xE1);	// "11100001"

	BitUtils::setBitValue(&byte, 7, 0);

	assert( byte == 0x61);	// "01100001"

}

void testSetRtpHeaderValue(){

	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	Quartet quartet;
	BitUtils::setRtpHeaderValue(&quartet, 0, 32, 0);

	assert( 0x0 == quartet.bytes[0]);
	assert( 0x0 == quartet.bytes[1]);
	assert( 0x0 == quartet.bytes[2]);
	assert( 0x0 == quartet.bytes[3]);

	uint32_t value = 0x00F0; 	//"0000000011110000"
	int startPos = 0;
	int nBits = 8;

	BitUtils::setRtpHeaderValue(&quartet, startPos, nBits, value);
	assert( 0xF0 == quartet.bytes[0]);

	//reset quartet
	BitUtils::setRtpHeaderValue(&quartet, 0, 32, 0);

	value = 0x2;
	startPos = 0;
	nBits = 2;

	BitUtils::setRtpHeaderValue(&quartet, startPos, nBits, value);
	assert( 0x80 == quartet.bytes[0]);

	value = 0x1;
	startPos = 2;
	nBits = 1;

	BitUtils::setRtpHeaderValue(&quartet, startPos, nBits, value);
	assert( 0xa0 == quartet.bytes[0]);

	value = 0x1;
	startPos = 8;
	nBits = 1;

	BitUtils::setRtpHeaderValue(&quartet, startPos, nBits, value);
	assert( 0x80 == quartet.bytes[1]);

	value = 0x8;
	startPos = 9;
	nBits = 7;

	BitUtils::setRtpHeaderValue(&quartet, startPos, nBits, value);
	assert( 0x88 == quartet.bytes[1]);

	value = 0x1234;
	startPos = 16;
	nBits = 16;

	BitUtils::setRtpHeaderValue(&quartet, startPos, nBits, value);
	assert( 0x12 == quartet.bytes[2]);
	assert( 0x34 == quartet.bytes[3]);
}

/**
 * test function ParsingUtils::getNumberOfLines(string sipMessage);
 *
 */
void testGetNumberOfLines(){
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	initializeInviteMsg();
//	fprintf(stderr, "sipInviteMsgStr = \n%s", sipInviteMsgStr.c_str());

	int nOfLines = ParsingUtils::getNumberOfLines(sipInviteMsgStr);
	cout <<" nOfLines = " << nOfLines << endl;

	assert(23 == nOfLines);

}

void testExtractMethod() {
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	string requestLine = "INVITE sip:francisco@bestel.com:55060 SIP/2.0";
	string sipMethod = ParsingUtils::extractMethod(requestLine);
	assert(0 == sipMethod.compare("INVITE"));
}

void testExtractRequestUri() {
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	string requestLine = "INVITE sip:francisco@bestel.com:55060 SIP/2.0";
	string sipMethod = ParsingUtils::extractRequestUri(requestLine);

	string expectedRequestURI = "sip:francisco@bestel.com:55060";
	assert(0 == sipMethod.compare(expectedRequestURI));
}

void testParseSipMessageRequest2(){
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	initializeAckMsg();

	SipMessage * sipMsg = SipMessage::parseSipMessage(sipACKMsgStr);

	assert(true == sipMsg->isRequest());
	assert(false == sipMsg->isResponse());

	SipRequest * sipRequest = static_cast<SipRequest *>(sipMsg);

	assert(sipRequest->getMethod().compare("ACK") == 0);
}

/**
 * test the parsing of SIP Request
 */
void testParseSipMessageRequest(){
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	initializeInviteMsg();

	SipMessage * sipMsg = SipMessage::parseSipMessage(sipInviteMsgStr);

	assert(true == sipMsg->isRequest());
	assert(false == sipMsg->isResponse());

	SipRequest * sipRequest = static_cast<SipRequest *>(sipMsg);

	assert(sipRequest->getMethod().compare("INVITE") == 0);

	string expectedRequestUri = "sip:francisco@bestel.com:55060";
	assert(sipRequest->getRequestUri().compare(expectedRequestUri) == 0);

	string fromHdrValue = sipRequest->getHeader(SipHeader::FROM_HNAME);
	string expectedValue = string("<sip:200.57.7.195:55061;user=phone>;tag=GR52RWG346-34");
	assert(0 == fromHdrValue.compare(expectedValue));

	//	<<"To: \"francisco@bestel.com\" <sip:francisco@bestel.com:55060>"<< '\x0d' << '\x0a'
	string toHdrValue = sipRequest->getHeader(SipHeader::TO_HNAME);
	expectedValue = "\"francisco@bestel.com\" <sip:francisco@bestel.com:55060>";
	assert(0 == toHdrValue.compare(expectedValue));

	//	<<"Via: SIP/2.0/UDP 200.57.7.195:55061;branch=z9hG4bK291d90e31a47b225bd0ddff4353e9cc0" << '\x0d' << '\x0a'
	string viaHdrValue = sipRequest->getHeader(SipHeader::VIA_HNAME);
	expectedValue = "SIP/2.0/UDP 200.57.7.195:55061;branch=z9hG4bK291d90e31a47b225bd0ddff4353e9cc0";
	assert(0 == viaHdrValue.compare(expectedValue));

	//	<<"Call-ID: 12013223@200.57.7.195"<< '\x0d' << '\x0a'
	string callidHdrValue = sipRequest->getHeader(SipHeader::CALL_ID_HNAME);
	expectedValue = "12013223@200.57.7.195";
	assert(0 == callidHdrValue.compare(expectedValue));

	string callidStr = sipRequest->getCallID();
	expectedValue = "12013223@200.57.7.195";
	assert(0 == callidStr.compare(expectedValue));

	//	<<"CSeq: 1 INVITE"<< '\x0d' << '\x0a'
	string cseqHdrValue = sipRequest->getHeader(SipHeader::CSEQ_HNAME);
	expectedValue = "1 INVITE";
	assert(0 == cseqHdrValue.compare(expectedValue));

	//	<<"Contact: <sip:200.57.7.195:5060>"<< '\x0d' << '\x0a'
	string contactHdrValue = sipRequest->getHeader(SipHeader::CONTACT_HNAME);
	expectedValue = "<sip:200.57.7.195:5060>";
	assert(0 == contactHdrValue.compare(expectedValue));

	//	<<"Content-Type: application/sdp"<< '\x0d' << '\x0a'
	string contentTypeHdrValue = sipRequest->getHeader(SipHeader::CONTENT_TYPE_HNAME);
	expectedValue = "application/sdp";
	assert(0 == contentTypeHdrValue.compare(expectedValue));

	string contentStr = sipRequest->getContent();
	assert(! contentStr.empty());
//	cout << "content String is:\n" << contentStr;
}

void testExtractHeaderNameAndValue() {
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);
	string headerLine = string("From: <sip:200.57.7.195:55061;user=phone>;tag=GR52RWG346-34");

	string headerName = ParsingUtils::extractHeaderName(headerLine);
	assert(0 == headerName.compare(SipHeader::FROM_HNAME));
	string headerValue = ParsingUtils::extractHeaderValue(headerLine);
	string expectedValue = string("<sip:200.57.7.195:55061;user=phone>;tag=GR52RWG346-34");
	assert(0 == headerValue.compare(expectedValue));

	headerLine =string("To: \"francisco@bestel.com\" <sip:francisco@bestel.com:55060>");
	headerName = ParsingUtils::extractHeaderName(headerLine);
	assert(0 == headerName.compare(SipHeader::TO_HNAME));
	headerValue = ParsingUtils::extractHeaderValue(headerLine);
	expectedValue = string("\"francisco@bestel.com\" <sip:francisco@bestel.com:55060>");
	assert(0 == headerValue.compare(expectedValue));

	headerLine = string("Call-ID: 12013223@200.57.7.195");
	headerName = ParsingUtils::extractHeaderName(headerLine);
	assert(0 == headerName.compare(SipHeader::CALL_ID_HNAME));
	headerValue = ParsingUtils::extractHeaderValue(headerLine);
	expectedValue = string("12013223@200.57.7.195");
	assert(0 == headerValue.compare(expectedValue));

	headerLine = string("CSeq: 1 INVITE");
	headerName = ParsingUtils::extractHeaderName(headerLine);
	assert(0 == headerName.compare(SipHeader::CSEQ_HNAME));
	headerValue = ParsingUtils::extractHeaderValue(headerLine);
	expectedValue = "1 INVITE";
	assert(0 == headerValue.compare(expectedValue));

}

void testSipServerGetContactAddr() {
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);
	cout << "SipServer contact Address:" << nmps::SipServer::getContactAddress() << endl;
}

void testCreateSipResponse() {
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	initializeInviteMsg();

	SipMessage * sipMsg = SipMessage::parseSipMessage(sipInviteMsgStr);
	SipRequest * sipRequest = static_cast<SipRequest *>(sipMsg);
	SipDialog * sipDialog = new SipDialog(sipRequest->getCallID());
	sipRequest->setSipDialog(sipDialog);

	sipDialog->localUriAndParams = sipRequest->getHeader(SipHeader::TO_HNAME);
	sipDialog->peerUriAndParams = sipRequest->getHeader(SipHeader::FROM_HNAME);

	SipResponse * sipResponse = sipRequest->createResponse(200, "OK");

	string offerSDP = sipRequest->getContent();
	string answerSDP = SipMessage::createAnswerSDP(offerSDP);
//	cout << "newly created answerSDP: \n" << answerSDP;

	sipResponse->setContent("application/sdp", answerSDP);

//	cout << "newly created response: \n" << sipResponse->toString();

	// check the targetAddress was calculated correctly
	//"Via: SIP/2.0/UDP 200.57.7.195:55061;branch=z9hG4bK291d90e31a47b225bd0ddff4353e9cc0" << '\x0d' << '\x0a'
	Hop * nextHop = sipResponse->getTargetAddr();
	string expectedIP = string("200.57.7.195");
	assert(0 == expectedIP.compare(nextHop->ip));

	assert(55061 == nextHop->port);

	assert(UDP == nextHop->transport);

}


void testExtractRTPInfo(){
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);
	stringstream ss;
	ss 		<<"v=0"<< '\x0d' << '\x0a'
			<<"o=Clarent 120386 120387 IN IP4 200.57.7.196"<< '\x0d' << '\x0a'
			<<"s=Clarent C5CM"<< '\x0d' << '\x0a'
			<<"c=IN IP4 200.57.7.196"<< '\x0d' << '\x0a'
			<<"t=0 0"<< '\x0d' << '\x0a'
			<<"m=audio 40376 RTP/AVP 8 18 4 0"<< '\x0d' << '\x0a'
			<<"a=rtpmap:8 PCMA/8000"<< '\x0d' << '\x0a'
			<<"a=rtpmap:18 G729/8000"<< '\x0d' << '\x0a'
			<<"a=rtpmap:4 G723/8000"<< '\x0d' << '\x0a'
			<<"a=rtpmap:0 PCMU/8000"<< '\x0d' << '\x0a'
			<<"a=SendRecv"<< '\x0d' << '\x0a';

	string offerSDP = ss.str();



	string clientIP = SipMessage::extractRtpIP(offerSDP);
	unsigned int clientPort = SipMessage::extractRtpPort(offerSDP);

	string expectedIP = string("200.57.7.196");
	unsigned int expectedPort = 40376;

	assert(0 == expectedIP.compare(clientIP));
	assert(expectedPort == clientPort);

}

void testRadioStreamerState(){
	fprintf(stderr, "Running Unit Test ==> \"%s\"\n", __func__);

	RadioChannel radioChannel;
	radioChannel.channelNumber = 1;
	radioChannel.channelID = "12345";
	radioChannel.title = "KPCC";
	radioChannel.playlistURL = "http://yp.shoutcast.com/sbin/tunein-station.pls?id=179361";
	//create the default RadioStreamer
	RadioStreamer * defaultRadioStreamer = new RadioStreamer(radioChannel);

	assert(false == defaultRadioStreamer->isStreamingStarted());
	assert(false == defaultRadioStreamer->isPaused());
	assert(false == defaultRadioStreamer->isStoped());

	defaultRadioStreamer->startStreaming();

	assert(true == defaultRadioStreamer->isStreamingStarted());
	assert(false == defaultRadioStreamer->isPaused());
	assert(false == defaultRadioStreamer->isStoped());

	sleep(5);

	fprintf(stderr, "radio will be paused for 5 seconds!\n");
	// pause for 5 seconds
	defaultRadioStreamer->pauseStreaming();

	assert(true == defaultRadioStreamer->isStreamingStarted());
	assert(true == defaultRadioStreamer->isPaused());
	assert(false == defaultRadioStreamer->isStoped());

	sleep(5);

	fprintf(stderr, "radio will be resumed now!\n");
	// resume and last for another 5 seconds and exit
	defaultRadioStreamer->resumeStreaming();

	sleep(5);
	fprintf(stderr, "radio will be stopped now!\n");
	defaultRadioStreamer->stopStreaming();

	assert(false == defaultRadioStreamer->isStreamingStarted());
	assert(false == defaultRadioStreamer->isPaused());
	assert(true == defaultRadioStreamer->isStoped());

	sleep(5);
	fprintf(stderr, "radio will be started again!\n");
	defaultRadioStreamer->startStreaming();

	assert(true == defaultRadioStreamer->isStreamingStarted());
	assert(false == defaultRadioStreamer->isPaused());
	assert(false == defaultRadioStreamer->isStoped());

	sleep(5);
	fprintf(stderr, "radio will be stopped now!\n");
	defaultRadioStreamer->stopStreaming();
	assert(false == defaultRadioStreamer->isStreamingStarted());
	assert(false == defaultRadioStreamer->isPaused());
	assert(true == defaultRadioStreamer->isStoped());

	pthread_join(defaultRadioStreamer->getRadioStreamerThread(), NULL);

}

int main(int argc, char ** argv)
{
	try {
		testGetBitValue();

		testSetBitValue();

		testSetRtpHeaderValue();

		testGetNumberOfLines();

		testExtractMethod();

		testExtractRequestUri();

		testParseSipMessageRequest();

		testParseSipMessageRequest2();

		testExtractHeaderNameAndValue();

		testSipServerGetContactAddr();

		testCreateSipResponse();

		testExtractRTPInfo();

//		testRadioStreamerState();

	} catch (NmpsException & e){
		cerr << e.description() << endl;
	}
	return EXIT_SUCCESS;
}
